﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlServerCe;
using System.Text.RegularExpressions;

using System.Threading;
using System.Reflection;

namespace SqlMiM.Common.Sql
{


    /// <summary>
    /// Manages open connections on a per-thread basis
    /// </summary>
    public class SqlCePoolConnection : IDisposable
    {
        // Unique by Thread an by ConnectionString
        [ThreadStatic]
        private static Dictionary<String, SqlCePoolConnection> pooledConnection;

 

        /// <summary>
        /// Pooled connection by user and by thread
        /// </summary>
        private static Dictionary<String, SqlCePoolConnection> PooledConnection
        {
            get
            {
                if (pooledConnection == null)
                    pooledConnection = new Dictionary<String, SqlCePoolConnection>(10);

                return pooledConnection;
            }
        }


        #region Static

        /// <summary>
        /// Get Pooled connection from Sql Ce Pool. If not exists, create one and return it
        /// </summary>
        public static SqlCePoolConnection CreateSqlCePooledConnection(String connectionString)
        {
            return CreateSqlCePooledConnection(connectionString, true);
        }

        /// <summary>
        /// Get Pooled connection from Sql Ce Pool. If not exists, create one and return it
        /// </summary>
        public static SqlCePoolConnection CreateSqlCePooledConnection(String connectionString, bool isPooled)
        {
            SqlCePoolConnection conn = null;

            if (isPooled)
            {
                // Get Pooled connection
                if (SqlCePoolConnection.PooledConnection.TryGetValue(connectionString, out conn))
                    return conn;

                // If no exists, create one
                conn = new SqlCePoolConnection(connectionString, true);

                // Add to pool
                SqlCePoolConnection.PooledConnection.Add(connectionString, conn);

                // return;
                return conn;
            }
            else
            {
                return new SqlCePoolConnection(connectionString, false);
            }
        }


        #endregion

        #region Singleton for LinqToSql

        /// <summary>
        /// SqlCeConnection. USE ONLY WITH LINQ TO SQL !
        /// </summary>
        public static SqlCeConnection GetLinToSqlCeConnection(String connectionString)
        {
            SqlCePoolConnection poolConn = CreateSqlCePooledConnection(connectionString, true);
            poolConn.Open();
            return poolConn.SqlCeConnection;
        }


        #endregion

        #region Connection, Transaction and Create transaction command

        // User Pool connection for current connection
        private bool usePooledConnection;

        // current transaction number
        private int currentSessionTransactionNumber;

        // current transaction
        private SqlCeTransaction sqlCeTransaction;

        /// <summary>
        /// Current Sql Ce Transaction
        /// </summary>
        public SqlCeTransaction SqlCeTransaction
        {
            get { return sqlCeTransaction; }
        }

        /// <summary>
        /// Private constructor. Create a connection Sql Ce
        /// </summary>
        private SqlCePoolConnection(string connectionString, bool isPooled)
        {
            this.SqlCeConnection = new SqlCeConnection(connectionString);
            this.usePooledConnection = isPooled;
        }

        /// <summary>
        /// Current Connection
        /// </summary>
        public SqlCeConnection SqlCeConnection { get; private set; }

        /// <summary>
        /// Create a command
        /// </summary>
        public SqlCeCommand CreateCommand()
        {
            return this.SqlCeConnection.CreateCommand();
        }

        /// <summary>
        /// Open a connection. If is used with pool, may take a connection already opened.
        /// </summary>
        public bool Open()
        {
            if (this.SqlCeConnection.State != ConnectionState.Open)
            {
                this.SqlCeConnection.Open();

                return true;
            }
            return false;
        }

        /// <summary>
        /// Disconnect
        /// </summary>
        public void Close()
        {
            if (this.usePooledConnection) return;

            if (this.SqlCeConnection.State != ConnectionState.Closed)
                this.SqlCeConnection.Close();

        }

        /// <summary>
        /// Begin a new transaction
        /// </summary>
        public void BeginTransaction()
        {
            this.currentSessionTransactionNumber++;

            if (this.currentSessionTransactionNumber == 1)
            {
                this.Open();

                if (this.sqlCeTransaction == null)
                    this.sqlCeTransaction = this.SqlCeConnection.BeginTransaction(IsolationLevel.ReadCommitted);
            }
        }

        /// <summary>
        /// End current transaction
        /// </summary>
        public void EndTransaction(bool commit)
        {
            this.currentSessionTransactionNumber--;

            if (this.currentSessionTransactionNumber <= 0)
            {

                if (this.sqlCeTransaction != null)
                {
                    if (commit)
                        this.sqlCeTransaction.Commit(CommitMode.Immediate);
                    else
                        this.sqlCeTransaction.Rollback();

                    this.sqlCeTransaction.Dispose();
                    this.sqlCeTransaction = null;
                }

                this.Close();

                this.currentSessionTransactionNumber = 0;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {

            if (this.SqlCeConnection != null && this.SqlCeConnection.State != ConnectionState.Closed)
                this.SqlCeConnection.Close();
        }

        #endregion

       
    }



}
